const alipay = require("easy-alipay");
const { Payment } = require("wechat-pay");
const svgCaptcha = require("svg-captcha");
const nodemailer = require("nodemailer");
const isBase64 = require("is-base64");
const _ = require("lodash");
const topClient = require("./../lib/alidayu/topClient");
const util = require("./util");

module.exports = (ctx, next) => {
  return {
    sendSmsCode: async (phone, code) => {
      const sms = await BaaS.Models.plugin.sms
        .query({
          where: {
            baas_id: ctx.baas.id
          }
        })
        .fetch();
      if (!sms || parseInt(sms.number) < 1) {
        // 日志记录
        BaaS.redis.rpushAsync(
          util.getVersionKey("baas_log_sms"),
          JSON.stringify({
            baas_id: ctx.baas.id,
            phone: phone,
            content: `尊敬的用户, 您的${
              ctx.baas.name
            }验证码是${code}，请及时输入验证码完成操作。`,
            status: 0
          })
        );
        throw new Error("Sorry, short message");
      }

      const TopClient = topClient.TopClient;
      const client = new TopClient({
        appkey: util.config("sms.appkey"),
        appsecret: util.config("sms.appsecret"),
        REST_URL: "http://gw.api.taobao.com/router/rest"
      });
      const result = await new Promise((resolve, reject) => {
        client.execute(
          "alibaba.aliqin.fc.sms.num.send",
          {
            extend: "",
            sms_type: "normal",
            sms_free_sign_name: util.config("sms.sms_free_sign_name"),
            sms_param: `{"name":"${ctx.baas.name}","code":"${code}"}`,
            rec_num: phone,
            sms_template_code: util.config("sms.sms_template_code")
          },
          (error, response) => {
            if (error) {
              reject(error);
            } else {
              resolve(response);
            }
          }
        );
      });

      // 扣短信量
      await BaaS.Models.plugin.sms
        .forge({
          id: sms.id,
          number: parseInt(sms.number) - 1
        })
        .save();

      // 日志记录
      BaaS.redis.rpushAsync(
        util.getVersionKey("baas_log_sms"),
        JSON.stringify({
          baas_id: ctx.baas.id,
          phone: phone,
          content: `尊敬的用户, 您的${
            ctx.baas.name
          }验证码是${code}，请及时输入验证码完成操作。`,
          status: 1
        })
      );
      return result;
    },
    captcha: async code => {
      const captchaImg = await BaaS.Models.plugin.captchaImg
        .query({
          where: {
            baas_id: ctx.baas.id,
            code: code
          }
        })
        .fetch();
      if (!captchaImg) {
        throw new Error("Sorry, not configured");
      }
      const captcha = svgCaptcha.create({
        size: captchaImg.length, // 验证码长度
        ignoreChars: captchaImg.exclude, // 验证码字符中排除 0o1i
        noise: captchaImg.line, // 干扰线条的数量
        color: captchaImg.color, // 验证码的字符是否有颜色，默认没有，如果设定了背景，则默认有
        background: captchaImg.bgcolor // 验证码图片背景颜色
      });
      return captcha;
    },
    /**
     * 获取支付宝支付链接
     * type 手机端mobile 电脑端pc
     * outTradeNo 订单号
     * totalFee 总价格
     * subject 商品名称
     * body 商品详情
     * showUrl 网站商品的展示地址
     * returnUrl 付完款后跳转的页面
     */
    alipay: async (
      type,
      outTradeNo,
      totalFee,
      subject,
      body,
      showUrl,
      returnUrl
    ) => {
      const alipayConfig = await BaaS.Models.plugin.payAlipay
        .query({
          where: {
            baas_id: ctx.baas.id
          }
        })
        .fetch();
      if (!alipayConfig) {
        throw new Error("Sorry, not configured");
      }

      const classInfo = await BaaS.Models.class
        .query({
          where: {
            baas_id: ctx.baas.id,
            id: alipayConfig.class_id
          }
        })
        .fetch();
      const funcInfo = await BaaS.Models.classFunction
        .query({
          where: {
            baas_id: ctx.baas.id,
            class_id: alipayConfig.class_id,
            id: alipayConfig.function_id
          }
        })
        .fetch();

      const notifyUrl = `${util.config("host")}/2.0/appid/${
        ctx.baas.appid
      }/appkey/${ctx.baas.appkey}/class/${classInfo.name}/function/${
        funcInfo.name
      }`;
      const payType =
        type === "mobile" ? "createDirectPayWap" : "createDirectPay";

      return await alipay.Payment[payType](
        alipayConfig.partner,
        alipayConfig.key,
        alipayConfig.account,
        subject,
        outTradeNo,
        totalFee,
        body,
        showUrl,
        notifyUrl,
        returnUrl
      );
    },
    /**
     * alipay支付回调验证
     * mobile pc
     */
    alipayNotifyValidate: async type => {
      const notifyData = ctx.post;
      const alipayConfig = await BaaS.Models.plugin.payAlipay
        .query({
          where: {
            baas_id: ctx.baas.id
          }
        })
        .fetch();
      const payType =
        type === "mobile" ? "directPayNotifyWap" : "directPayNotify";

      return alipay.Notification[payType](
        notifyData,
        alipayConfig.partner,
        alipayConfig.key
      );
    },
    /**
    * 返回微信支付参数
    * order参数
    {
      body: "吮指原味鸡 * 1",
      attach: "{'部位':'三角'}",
      out_trade_no: "kfc" + +new Date(),
      total_fee: parseFloat(0.01) * 100,
      spbill_create_ip: "127.0.0.1",
      openid: "oLh8Mw94s2dZeBeNZuAkGvkTczGM",
      trade_type: "JSAPI"
    }
    */
    wxpay: async order => {
      const wxPay = await BaaS.Models.plugin.payWexin
        .query({
          where: {
            baas_id: ctx.baas.id
          }
        })
        .fetch();
      if (!wxPay) {
        throw new Error("Sorry, not configured");
      }

      const classInfo = await BaaS.Models.class
        .query({
          where: {
            baas_id: ctx.baas.id,
            id: wxPay.class_id
          }
        })
        .fetch();
      const funcInfo = await BaaS.Models.classFunction
        .query({
          where: {
            baas_id: ctx.baas.id,
            class_id: wxPay.class_id,
            id: wxPay.function_id
          }
        })
        .fetch();

      const notifyUrl = `${util.config("host")}/2.0/appid/${
        ctx.baas.appid
      }/appkey/${ctx.baas.appkey}/class/${classInfo.name}/function/${
        funcInfo.name
      }`;

      const payment = new Payment({
        partnerKey: wxPay.key,
        appId: wxPay.appid,
        mchId: wxPay.mchid,
        notifyUrl: notifyUrl,
        pfx: wxPay.certificate
      });
      return await new Promise((resolve, reject) => {
        payment.getBrandWCPayRequestParams(order, (err, payargs) => {
          if (err) return reject(err);
          resolve(payargs);
        });
      });
    },
    /**
     * 微信支付回调验证
     */
    wxpayNotifyValidate: async () => {
      const wxPay = await BaaS.Models.plugin.payWexin
        .query({
          where: {
            baas_id: ctx.baas.id
          }
        })
        .fetch();
      const classInfo = await BaaS.Models.class
        .query({
          where: {
            baas_id: ctx.baas.id,
            id: wxPay.class_id
          }
        })
        .fetch();
      const funcInfo = await BaaS.Models.classFunction
        .query({
          where: {
            baas_id: ctx.baas.id,
            class_id: wxPay.class_id,
            id: wxPay.function_id
          }
        })
        .fetch();

      const notifyUrl = `${util.config("host")}/2.0/appid/${
        ctx.baas.appid
      }/appkey/${ctx.baas.appkey}/class/${classInfo.name}/function/${
        funcInfo.name
      }`;

      const payment = new Payment({
        partnerKey: wxPay.key,
        appId: wxPay.appid,
        mchId: wxPay.mchid,
        notifyUrl: notifyUrl,
        pfx: wxPay.certificate
      });

      if (payment._getSign(ctx.xml) === ctx.xml.sign) {
        return ctx.xml;
      } else {
        return false;
      }
    },
    /**
    * 返回微信小程序支付参数
    * order参数
    {
      body: "吮指原味鸡 * 1",
      attach: "{'部位':'三角'}",
      out_trade_no: "kfc" + +new Date(),
      total_fee: parseFloat(0.01) * 100,
      spbill_create_ip: "127.0.0.1",
      openid: "oLh8Mw94s2dZeBeNZuAkGvkTczGM",
      trade_type: "JSAPI"
    }
    */
    wxapay: async order => {
      const wxaPay = await BaaS.Models.plugin.payWxa
        .query({
          where: {
            baas_id: ctx.baas.id
          }
        })
        .fetch();
      if (!wxaPay) {
        throw new Error("Sorry, not configured");
      }

      const classInfo = await BaaS.Models.class
        .query({
          where: {
            baas_id: ctx.baas.id,
            id: wxaPay.class_id
          }
        })
        .fetch();
      const funcInfo = await BaaS.Models.classFunction
        .query({
          where: {
            baas_id: ctx.baas.id,
            class_id: wxaPay.class_id,
            id: wxaPay.function_id
          }
        })
        .fetch();

      const notifyUrl = `${util.config("host")}/2.0/appid/${
        ctx.baas.appid
      }/appkey/${ctx.baas.appkey}/class/${classInfo.name}/function/${
        funcInfo.name
      }`;

      const payment = new Payment({
        partnerKey: wxaPay.key,
        appId: wxaPay.appid,
        mchId: wxaPay.mchid,
        notifyUrl: notifyUrl,
        pfx: wxaPay.certificate
      });
      return await new Promise((resolve, reject) => {
        payment.getBrandWCPayRequestParams(order, (err, payargs) => {
          if (err) return reject(err);
          resolve(payargs);
        });
      });
    },
    /**
     * 微信小程序支付回调验证
     */
    wxapayNotifyValidate: async () => {
      const wxaPay = await BaaS.Models.plugin.payWxa
        .query({
          where: {
            baas_id: ctx.baas.id
          }
        })
        .fetch();
      const classInfo = await BaaS.Models.class
        .query({
          where: {
            baas_id: ctx.baas.id,
            id: wxaPay.class_id
          }
        })
        .fetch();
      const funcInfo = await BaaS.Models.classFunction
        .query({
          where: {
            baas_id: ctx.baas.id,
            class_id: wxaPay.class_id,
            id: wxaPay.function_id
          }
        })
        .fetch();

      const notifyUrl = `${util.config("host")}/2.0/appid/${
        ctx.baas.appid
      }/appkey/${ctx.baas.appkey}/class/${classInfo.name}/function/${
        funcInfo.name
      }`;

      const payment = new Payment({
        partnerKey: wxaPay.key,
        appId: wxaPay.appid,
        mchId: wxaPay.mchid,
        notifyUrl: notifyUrl,
        pfx: wxaPay.certificate
      });

      if (payment._getSign(ctx.xml) === ctx.xml.sign) {
        return ctx.xml;
      } else {
        return false;
      }
    },
    /**
    mailOptions = {
        from: '"白小明 👻" <1604583867@qq.com>', // 发件人
        to: '1096239306@qq.com, xx2@qq.com', // 收件人
        subject: 'Hello ✔', // 主题
        text: '这是一封来自 Node.js 的测试邮件', // plain text body
        html: '<b>这是一封来自 Node.js 的测试邮件</b>', // html body
        // 下面是发送附件，不需要就注释掉
        attachments: [{
                filename: 'test.md',
                path: './test.md'
            },
            {
                filename: 'content',
                content: '发送内容'
            }
        ]
    };
     */
    sendMail: async mailOptions => {
      if (mailOptions.attachments && !_.isArray(mailOptions.attachments)) {
        throw new Error("Sorry, attachments must be array");
      }
      if (mailOptions.attachments && _.isArray(mailOptions.attachments)) {
        for (const option of mailOptions.attachments) {
          if (option.path) {
            if (
              !_.startsWith(option.path, "http://") &&
              !_.startsWith(option.path, "https://") &&
              !isBase64(option.path)
            ) {
              option.path = ctx.getAppDir(option.path);
            }
          }
        }
      }

      const mail = await BaaS.Models.plugin.mail
        .query({
          where: {
            baas_id: ctx.baas.id
          }
        })
        .fetch();
      const transporter = nodemailer.createTransport({
        host: mail.host, // 主机
        secureConnection: mail.secureConnection, // 使用 SSL
        port: mail.port, // SMTP 端口
        auth: {
          user: mail.user,
          pass: mail.pass
        }
      });
      return await new Promise((resolve, reject) => {
        transporter.sendMail(mailOptions, (error, info) => {
          transporter.close(); // 如果没用，关闭连接池
          if (error) return reject(error);
          resolve(info);
        });
      });
    }
  };
};
